#include <stdio.h>
#include "memory_pool.h"
#include <string.h>
#include <malloc.h>
#define ADATAUNIT  4
#define MEMPOOL_ALIGNMENT 4      /*<! 机器的字节对齐数*/
/*! 
 * \brief 内存块结构体
 */
typedef struct memory_block {
    struct memory_block*   p_next; /*<! 指向下一片内存*/
    ULONG          n_size;        /*<!每个block的总小块数*/
    ULONG          nfree_left;   /*<!剩余小块的数目*/
    ULONG          nfirst_index; /*<!第一个可用小块的索引号*/ 
    char           adata[1];     /*<!第一个小块前四个字节，不被使用*/
}memory_block;

/*!
 * \brief 内存池结构体
 */
typedef struct memory_pool {
    memory_block*  pBlock;        /*<! 第一块分配内存*/
    ULONG         n_unit_size;     /*<! 内存池分配单元的大小*/
    ULONG         n_init_size;     /*<! 初始分配的内存大小*/
    ULONG         n_grow_size;     /*<! 之后每次分配的大小*/
}memory_pool;

memory_pool *mp; /*<! 内存池全局变量*/

/*!
 * \brief 申请内存块
 */
static void* block_new(ULONG nTypes, ULONG n_unit_size)
{
    memory_block*  my_block;
    my_block = (memory_block *) malloc(sizeof(memory_block) + nTypes * n_unit_size);
    my_block->n_size = nTypes; /*<! 申请时，块内初始化*/
    my_block->nfree_left = nTypes;
    my_block->nfirst_index = 0;
    my_block->p_next = NULL;
    return my_block;
}
/*
 * \brief 回收内存块
 */
static void  block_delete(void *p )
{
    free(p);
}
int
init_memorypool(ULONG _n_unit_size,ULONG _n_init_size,ULONG _n_grow_size)
{
    mp = (memory_pool*)malloc(sizeof(memory_pool));
    if(NULL == mp)
    	return 1;
    mp->pBlock      = NULL;               
    mp->n_init_size   = _n_init_size;     /*<! 每个块分配的索引小块数*/
    mp->n_grow_size   = _n_grow_size;     /*<! 增长块的内存索引小块数*/

    /*<! 设置小块的大小*/
    if ( _n_unit_size > 4 )                    
       mp->n_unit_size = (_n_unit_size + (MEMPOOL_ALIGNMENT-1)) & ~(MEMPOOL_ALIGNMENT-1); 
    else
       mp->n_unit_size = 4;
    return 0;
}

static void  
init_block(memory_block* new_block ,ULONG n_size,ULONG n_unit_size )                       /*<!初始化分配的新块,n_size为该块的总索引数*/
{
    char *pdata = new_block->adata;   /*<!从第二个小块开始设置索引，第一个小块返回提供使用*/
    ULONG *mini_block_head;
    ULONG i= 1;
    for( ;i < n_size; ++i) {  /*<!设置每个小块的索引头,0号返回给该次申请者使用*/
        mini_block_head = (ULONG *)(pdata+n_unit_size*i +ADATAUNIT);
        *mini_block_head = i+1;
  //    printf("memory size:%x,%u\n",mini_block_head,*mini_block_head);
    }
    new_block->nfirst_index = 1;
    new_block->nfree_left = n_size-1;
}

void* alloc_node()
{
    if(NULL == mp) {
        return NULL;	
    }
    if( !mp->pBlock ) { /*<! 当前内存池尚无内存块，第一次分配*/
        mp->pBlock = (memory_block *) block_new (mp->n_init_size, mp->n_unit_size);
        init_block(mp->pBlock ,mp->n_init_size,mp->n_unit_size);
        return (void *) (mp->pBlock->adata+ADATAUNIT);
    }

    memory_block* pMyBlock = mp->pBlock;  /*<! 从链表头部pBlock开始*/
    while (pMyBlock && !pMyBlock->nfree_left )  /*<! 搜索可用内存快*/
        pMyBlock = pMyBlock->p_next;
    if ( pMyBlock ) { /*<! 尚有可用的内存快*/
        char* pFree = (char *) ( (ULONG)pMyBlock->adata+( pMyBlock->nfirst_index*mp->n_unit_size)+ADATAUNIT );
        pMyBlock->nfirst_index = *( (ULONG *)pFree );                                                     /*<! 每小块的头部两字节记录了下一个可用索引号*/                
        pMyBlock->nfree_left--;    
        return (void*)pFree;
    }  

    else { /*<! 找不到可用内存块*/
        if ( !mp->n_grow_size )
        return NULL;
        pMyBlock = (memory_block *)block_new (mp->n_grow_size, mp->n_unit_size);
        if ( !pMyBlock )
        return NULL;

        pMyBlock->p_next = mp->pBlock; /*<!新块插入到块链表头部*/
        mp->pBlock = pMyBlock;

        init_block( pMyBlock ,mp->n_grow_size,mp->n_unit_size);

        return (void*)(pMyBlock->adata+ADATAUNIT);
    }
}


int free_node(void* pFree )
{
    if(NULL == pFree)
    	return 1;
    ULONG* pfree_us;   
    ULONG  pfree_index, pHead;
    pfree_us = (ULONG *)pFree;
    memory_block* pMyBlock = mp->pBlock;
    memory_block* pre_pBlock = NULL;

    while ( ((ULONG)pMyBlock->adata > (ULONG)pfree_us) || ((ULONG)pfree_us >= ((ULONG)pMyBlock->adata + pMyBlock->n_size*mp->n_unit_size)) ) { /*<!定位pFree所在的块*/
         pre_pBlock = pMyBlock;
         pMyBlock = pMyBlock->p_next;
    }
    if(pMyBlock == NULL)  /*<!pFree不是属于内存池管理的内存*/
        return 2;

    /*<!回收pFree*/
    pMyBlock->nfree_left++;                 
    pHead = pMyBlock->nfirst_index; /*<!第一个可用索引*/
    pfree_index = ( (ULONG)pfree_us-(ULONG)pMyBlock->adata -ADATAUNIT)/mp->n_unit_size;  /*<!获取pFree的索引号*/
    pMyBlock->nfirst_index = pfree_index; /*<!pFree插入到可用块首*/
    *pfree_us = pHead; /*<!之前的块首链入*/
     
    /*<!判断是否需要将Block内存返回给系统*/
     if (pMyBlock->nfree_left  == pMyBlock->n_size ) {
        if(pre_pBlock)   /*<!删除的不是第一个memory_block*/
            pre_pBlock->p_next = pMyBlock->p_next;
        mp->pBlock = pMyBlock->p_next; /*<!删除的是第一个memory_block*/
        block_delete(pMyBlock);
    }
   return 0;
}

int delete_memorypool()   /*<!析构函数释放所有的memory_block，即使用户忘记free掉自己申请的内存也不会发生内存泄漏*/
{
    if(NULL == mp)
        return 1;
    memory_block*   my_block = mp->pBlock;
    memory_block*   next_block = NULL;
    while( my_block ) {
        next_block = my_block->p_next;
        block_delete( (void *)my_block);
        printf("free pool memory\n");
        my_block = next_block;
    }
    free(mp);
    mp = NULL;
    return 0;
}

